﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Koopakiller.Numerics.Test
{
    [TestClass]
    public class MatrixTest
    {
        #region resize

        //? greater x & y
        [TestMethod]
        public void TestResizeA1()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(4, 4, ResizeMode.FillOne);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(1, m[3, 3]);
            Assert.AreEqual(1, m[0, 3]);
            Assert.AreEqual(1, m[3, 0]);

            Assert.AreEqual(4, m.SizeX);
            Assert.AreEqual(4, m.SizeY);
        }
        [TestMethod]
        public void TestResizeA2()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(4, 4, ResizeMode.FillZero);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(0, m[3, 3]);
            Assert.AreEqual(0, m[0, 3]);
            Assert.AreEqual(0, m[3, 0]);

            Assert.AreEqual(4, m.SizeX);
            Assert.AreEqual(4, m.SizeY);
        }
        [TestMethod]
        public void TestResizeA3()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(4, 4, ResizeMode.Identity);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(1, m[3, 3]);
            Assert.AreEqual(0, m[0, 3]);
            Assert.AreEqual(0, m[3, 0]);

            Assert.AreEqual(4, m.SizeX);
            Assert.AreEqual(4, m.SizeY);
        }

        //? greater x
        [TestMethod]
        public void TestResizeB1()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(4, 3, ResizeMode.FillOne);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(1, m[3, 0]);
            Assert.AreEqual(1, m[3, 2]);

            Assert.AreEqual(4, m.SizeX);
            Assert.AreEqual(3, m.SizeY);
        }
        [TestMethod]
        public void TestResizeB2()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(4, 3, ResizeMode.FillZero);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(0, m[3, 0]);
            Assert.AreEqual(0, m[3, 2]);

            Assert.AreEqual(4, m.SizeX);
            Assert.AreEqual(3, m.SizeY);
        }
        [TestMethod]
        public void TestResizeB3()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(4, 3, ResizeMode.Identity);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(0, m[3, 0]);
            Assert.AreEqual(0, m[3, 2]);

            Assert.AreEqual(4, m.SizeX);
            Assert.AreEqual(3, m.SizeY);
        }

        //? greater y
        [TestMethod]
        public void TestResizeC1()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(3, 4, ResizeMode.FillOne);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(1, m[0, 3]);
            Assert.AreEqual(1, m[2, 3]);

            Assert.AreEqual(3, m.SizeX);
            Assert.AreEqual(4, m.SizeY);
        }
        [TestMethod]
        public void TestResizeC2()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(3, 4, ResizeMode.FillZero);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(0, m[0, 3]);
            Assert.AreEqual(0, m[2, 3]);

            Assert.AreEqual(3, m.SizeX);
            Assert.AreEqual(4, m.SizeY);
        }
        [TestMethod]
        public void TestResizeC3()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Resize(3, 4, ResizeMode.Identity);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(3, m[2, 0]);
            Assert.AreEqual(7, m[0, 2]);
            Assert.AreEqual(9, m[2, 2]);
            Assert.AreEqual(0, m[0, 3]);
            Assert.AreEqual(0, m[2, 3]);

            Assert.AreEqual(3, m.SizeX);
            Assert.AreEqual(4, m.SizeY);
        }
        [TestMethod]
        public void TestResizeD1()
        {
            Matrix m = new Matrix();
            m.Resize(2, 2, ResizeMode.Identity);
            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(0, m[1, 0]);
            Assert.AreEqual(0, m[0, 1]);
            Assert.AreEqual(1, m[1, 1]);

            Assert.AreEqual(2, m.SizeX);
            Assert.AreEqual(2, m.SizeY);
        }

        #endregion

        #region identity matrix

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestM1()
        {
            try
            {
                var m = Matrix.CreateIdentityMatrix(-1);
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Test0()
        {
            var m = Matrix.CreateIdentityMatrix(0);
            Assert.AreEqual(0, m.SizeX);
            Assert.AreEqual(0, m.SizeY);

        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Test1()
        {
            var m = Matrix.CreateIdentityMatrix(1);
            Assert.AreEqual(1, m.SizeX);
            Assert.AreEqual(1, m.SizeY);

            Assert.AreEqual(1, m[0, 0]);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Test2()
        {
            var m = Matrix.CreateIdentityMatrix(2);
            Assert.AreEqual(2, m.SizeX);
            Assert.AreEqual(2, m.SizeY);

            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(0, m[0, 1]);
            Assert.AreEqual(0, m[1, 0]);
            Assert.AreEqual(1, m[1, 1]);

        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Test5()
        {
            var m = Matrix.CreateIdentityMatrix(5);
            Assert.AreEqual(5, m.SizeX);
            Assert.AreEqual(5, m.SizeY);

            Assert.AreEqual(1, m[0, 0]);
            Assert.AreEqual(0, m[4, 0]);
            Assert.AreEqual(1, m[2, 2]);
            Assert.AreEqual(0, m[0, 4]);
            Assert.AreEqual(1, m[4, 4]);
        }

        #endregion

        #region INotifyPropertyChanged

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestSizeX()
        {
            Matrix m = new Matrix(5, 5);
            m.PropertyChanged += (s, e) =>
            {
                Assert.AreEqual("SizeX", e.PropertyName);
            };

            m.Resize(3, 5, ResizeMode.FillZero);
        }

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestSizeY()
        {
            Matrix m = new Matrix(5, 5);
            m.PropertyChanged += (s, e) =>
            {
                Assert.AreEqual("SizeY", e.PropertyName);
            };

            m.Resize(5, 3, ResizeMode.FillZero);
        }


        #endregion

        #region Add

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestAdd1()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4);
            Matrix m2 = new Matrix(2, 1, 2, 3, 4);
            var r = m1 + m2;
            Assert.AreEqual(new Matrix(2, 2, 4, 6, 8), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestAdd2()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4);
            Matrix m2 = new Matrix(2, -1, -2, -3, -4);
            var r = m1 + m2;
            Assert.AreEqual(new Matrix(2, 0, 0, 0, 0), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestAdd3()
        {
            Matrix m1 = new Matrix(2, -1, -2, -3, -4);
            Matrix m2 = new Matrix(2, -1, -2, -3, -4);
            var r = m1 + m2;
            Assert.AreEqual(new Matrix(2, -2, -4, -6, -8), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestAdd4()
        {
            try
            {
                Matrix m1 = new Matrix(2, -1, -2, -3, -4);
                Matrix m2 = new Matrix(4, -1, -2, -3, -4);
                var r = m1 + m2;
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestAdd5()
        {
            Matrix m1 = new Matrix(0, 0);
            Matrix m2 = new Matrix(0, 0);
            var r = m1 + m2;
            Assert.AreEqual(new Matrix(0, 0), r);
        }

        #endregion

        #region Subtract

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestSubtract1()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4);
            Matrix m2 = new Matrix(2, 1, 2, 3, 4);
            var r = m1 - m2;
            Assert.AreEqual(new Matrix(2, 0, 0, 0, 0), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestSubtract2()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4);
            Matrix m2 = new Matrix(2, -1, -2, -3, -4);
            var r = m1 - m2;
            Assert.AreEqual(new Matrix(2, 2, 4, 6, 8), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestSubtract3()
        {
            Matrix m1 = new Matrix(2, -1, -2, -3, -4);
            Matrix m2 = new Matrix(2, -1, -2, -3, -4);
            var r = m1 - m2;
            Assert.AreEqual(new Matrix(2, 0, 0, 0, 0), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestSubtract4()
        {
            try
            {
                Matrix m1 = new Matrix(2, -1, -2, -3, -4);
                Matrix m2 = new Matrix(4, -1, -2, -3, -4);
                var r = m1 - m2;
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestSubtract5()
        {
            Matrix m1 = new Matrix(0, 0);
            Matrix m2 = new Matrix(0, 0);
            var r = m1 - m2;
            Assert.AreEqual(new Matrix(0, 0), r);
        }

        #endregion

        #region Multiply

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestMultiply1()
        {
            Matrix m1 = new Matrix(2, 2, 2, 2, 2);
            Matrix m2 = new Matrix(2, 2, 2, 2, 2);
            var r = m1 * m2;
            Assert.AreEqual(new Matrix(2, 8, 8, 8, 8), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestMultiply2()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4, 5, 6);
            Matrix m2 = new Matrix(3, 9, 8, 7, 6, 5, 4);
            var r = m1 * m2;
            Assert.AreEqual(new Matrix(3, 21, 18, 15, 51, 44, 37, 81, 70, 59), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestMultiply3()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4, 5, 6);
            Matrix m2 = new Matrix(2, 1, 2, 3, 4, 5, 6);
            try
            {
                var r = m1 * m2;
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }

        #endregion

        #region Multiply (Scalar)

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestMultiplyScalarA1()
        {
            Matrix m1 = new Matrix(2, 2, 2, 2, 2);
            double d = -3;
            var r = m1 * d;
            Assert.AreEqual(new Matrix(2, -6, -6, -6, -6), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestMultiplyScalarA2()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4, 5, 6);
            double d = -3;
            var r = m1 * d;
            Assert.AreEqual(new Matrix(2, -3, -6, -9, -12, -15, -18), r);
        }

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestMultiplyScalarB1()
        {
            Matrix m1 = new Matrix(2, 2, 2, 2, 2);
            double d = 12;
            var r = d * m1;
            Assert.AreEqual(new Matrix(2, 24, 24, 24, 24), r);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestMultiplyScalarB2()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4, 5, 6);
            double d = 12;
            var r = d * m1;
            Assert.AreEqual(new Matrix(2, 12, 24, 36, 48, 60, 72), r);
        }

        #endregion

        #region determinant

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant1a()
        {
            Matrix m = new Matrix(1, 1D);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(1, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant1b()
        {
            Matrix m = new Matrix(1, 2D);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(2, d);
        }

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant2a()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(-2, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant2b()
        {
            Matrix m = new Matrix(2, 10, 100, 1000, 10000);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(0, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant2c()
        {
            Matrix m = new Matrix(2, 9, 7, 5, 3);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(-8, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant3a()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(0, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant3b()
        {
            Matrix m = new Matrix(3, 10, 5, 2, 5, 2, 10, 2, 10, 5);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(-833, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant5a()
        {
            Matrix m = new Matrix(5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(0, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant5b()
        {
            Matrix m = new Matrix(5, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 3, 3, 3, 1, 2, 3, 4, 4, 1, 2, 3, 4, 5);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(1, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant9()
        {
            Matrix m = new Matrix(9, 1, 2, 3, 2, 1, 4, 5, 7, 4,
                                     3, 5, 7, 5, 3, 2, 4, 5, 6,
                                     7, 8, 5, 1, 9, 0, 7, 32, 8,
                                     -4, 6, 7, 2, -7, 33, 7, 5, 1,
                                     88, 9, 5, 4, 3, 2, 1, 3, 5,
                                     6, 7, 8, 6, 5, 4, 3, 2, 4,
                                     5, 6, 7, 8, 9, 0, 8, 6, 5,
                                     4, 3, 7, 4, 6, 3, 687, 2, 4,
                                     5, 7, 8, 4, 7, 2, 1, 3, 1);
            var d = Matrix.Determinant(m);
            Assert.AreEqual(-4073625920, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestDeterminant10()
        {
            //? not square
            Matrix m1 = new Matrix(3, 1, 2, 3, 4, 5, 6);
            try
            {
                Matrix.Determinant(m1);
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }

        #endregion

        #region IsMatrixSymmetric

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestIsMatrixSymmetric2a()
        {
            Matrix m = new Matrix(2, 1, 2, 2, 1);
            var d = Matrix.IsMatrixSymmetric(m);
            Assert.AreEqual(true, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestIsMatrixSymmetric2b()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4);
            var d = Matrix.IsMatrixSymmetric(m);
            Assert.AreEqual(false, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestIsMatrixSymmetric3a()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 2, 5, 7, 3, 7, 9);
            var d = Matrix.IsMatrixSymmetric(m);
            Assert.AreEqual(true, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestIsMatrixSymmetric3b()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            var d = Matrix.IsMatrixSymmetric(m);
            Assert.AreEqual(false, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestIsMatrixSymmetric4a()
        {
            Matrix m = new Matrix(4, 1, 2, 3, 4, 2, 9, 5, 6, 3, 5, 7, 8, 4, 6, 8, 0);
            var d = Matrix.IsMatrixSymmetric(m);
            Assert.AreEqual(true, d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestIsMatrixSymmetric4b()
        {
            Matrix m = new Matrix(4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
            var d = Matrix.IsMatrixSymmetric(m);
            Assert.AreEqual(false, d);
        }

        #endregion

        #region reciprocal

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestReciprocal2a()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4);
            var d = Matrix.Pow(m, -1);
            Assert.AreEqual(new Matrix(2, -2, 1, 1.5, -0.5), d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestReciprocal3a()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 1);
            var d = Matrix.Pow(m, -1);
            var r = new Matrix(3, -43D / 24D, 11D / 12D, -1D / 8D, 19D / 12D, -5D / 6D, 1D / 4D, -1 / 8D, 1 / 4D, -1 / 8D);
            //x Assert.AreEqual(r, d); //! inexact with double
            for (int x = 0; x < m.SizeX; ++x)
                for (int y = 0; y < m.SizeY; ++y)
                    Assert.AreEqual(r[x, y], d[x, y], 1e-10);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestReciprocalException1()
        {
            //? not square
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6);
            try
            {
                Matrix.Reciprocal(m);
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestReciprocalException2()
        {
            //? determinant = 0
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            try
            {
                Matrix.Reciprocal(m);
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }

        #endregion

        #region Pow

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPow0_0()
        {
            Matrix m = new Matrix();
            var d = Matrix.Pow(m, 0);
            Assert.AreEqual(new Matrix(), m);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPow0_2()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4);
            var d = Matrix.Pow(m, 0);
            Assert.AreEqual(new Matrix(2, 1, 0, 0, 1), d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPow0_3()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            var d = Matrix.Pow(m, 0);

            Assert.AreEqual(new Matrix(3, 1, 0, 0, 0, 1, 0, 0, 0, 1), d);
        }

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPow2_2()
        {
            Matrix m = new Matrix(2, 2, 2, 2, 2);
            var d = Matrix.Pow(m, 2);

            Assert.AreEqual(new Matrix(2, 8, 8, 8, 8), d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPow5_2()
        {
            Matrix m = new Matrix(2, 2, 2, 2, 2);
            var d = Matrix.Pow(m, 5);

            Assert.AreEqual(new Matrix(2, 512, 512, 512, 512), d);
        }

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPow2_3()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 1);
            var d = Matrix.Pow(m, 3);

            Assert.AreEqual(new Matrix(3, 300, 384, 324, 726, 921, 732, 784, 962, 580), d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPow5_3()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 1);
            var d = Matrix.Pow(m, 5);

            Assert.AreEqual(new Matrix(3, 49248, 61992, 46512, 116238, 146121, 108516, 113692, 142106, 100888), d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPowException1()
        {
            //? m.SizeX != m.SizeY
            try
            {
                var m = new Matrix(2, 1, 2, 3, 4, 5, 6);
                Matrix.Pow(m, 5);
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestPowException2()
        {
            //? exponent < -1
            try
            {
                var m = new Matrix(2, 1, 2, 3, 4, 5, 6);
                Matrix.Pow(m, -5);
                Assert.Fail("No exception");
            }
            catch (Exception ex)
            {
                Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType());
            }
        }

        #endregion

        #region negation

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestNegation1()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4);
            var d = -m;
            Assert.AreEqual(new Matrix(2, -1, -2, -3, -4), d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestNegation2()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            var d = -m;
            Assert.AreEqual(new Matrix(3, -1, -2, -3, -4, -5, -6, -7, -8, -9), d);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestNegation3()
        {
            Matrix m = new Matrix();
            var d = -m;
            Assert.AreEqual(new Matrix(), d);
        }

        #endregion

        #region == and !=

        [TestMethod]
        public void TestEqualNotEqual1()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4);
            Matrix m2 = new Matrix(2, 1, 2, 3, 4);
            Assert.AreEqual(true, m1 == m2);
            Assert.AreEqual(false, m1 != m2);
        }
        [TestMethod]
        public void TestEqualNotEqual2()
        {
            Matrix m1 = new Matrix(2, 1, 2, 3, 4);
            Matrix m2 = new Matrix(2, -1, -2, -3, -4);
            Assert.AreEqual(false, m1 == m2);
            Assert.AreEqual(true, m1 != m2);
        }
        [TestMethod]
        public void TestEqualNotEqual3()
        {
            Matrix m1 = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            Matrix m2 = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            Assert.AreEqual(true, m1 == m2);
            Assert.AreEqual(false, m1 != m2);
        }
        [TestMethod]
        public void TestEqualNotEqual4()
        {
            Matrix m1 = new Matrix(3, 1, 2, 3, -4, 5, 6, 7, -8, 9);
            Matrix m2 = new Matrix(3, -1, 2, 3, -4, 5, 6, 7, 8, 9);
            Assert.AreEqual(false, m1 == m2);
            Assert.AreEqual(true, m1 != m2);
        }

        #endregion

        #region ToString

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestToString1()
        {
            Matrix m = new Matrix();
            Assert.AreEqual("{ }", m.ToString());
        }

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestToString2()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4);
            Assert.AreEqual("{ { 1 | 2 }, { 3 | 4 } }", m.ToString());
        }

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void TestToString3()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            Assert.AreEqual("{ { 1 | 2 | 3 }, { 4 | 5 | 6 }, { 7 | 8 | 9 } }", m.ToString());
        }

        #endregion

        #region Flip

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Flip2()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4);
            m.Flip(false, true);
            Assert.AreEqual(new Matrix(2, 3, 4, 1, 2), m);
            m.Flip(true, false);
            Assert.AreEqual(new Matrix(2, 4, 3, 2, 1), m);
            m.Flip(true, true);
            Assert.AreEqual(new Matrix(2, 1, 2, 3, 4), m);
        }

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Flip3()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Flip(false, true);
            Assert.AreEqual(new Matrix(3, 7, 8, 9, 4, 5, 6, 1, 2, 3), m);
            m.Flip(true, false);
            Assert.AreEqual(new Matrix(3, 9, 8, 7, 6, 5, 4, 3, 2, 1), m);
            m.Flip(true, true);
            Assert.AreEqual(new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9), m);
        }

        #endregion

        #region Rotate

        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Rotate22()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(2, 3, 1, 4, 2), m);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(2, 4, 3, 2, 1), m);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(2, 2, 4, 1, 3), m);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Rotate33()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(3, 7, 4, 1, 8, 5, 2, 9, 6, 3), m);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(3, 9, 8, 7, 6, 5, 4, 3, 2, 1), m);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(3, 3, 6, 9, 2, 5, 8, 1, 4, 7), m);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Rotate32()
        {
            Matrix m = new Matrix(3, 1, 2, 3, 4, 5, 6);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(2, 4, 1, 5, 2, 6, 3), m);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(3, 6, 5, 4, 3, 2, 1), m);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(2, 3, 6, 2, 5, 1, 4), m);
        }
        [TestMethod(), TestCategory("Koopakiller.Numerics.Matrix")]
        public void Rotate23()
        {
            Matrix m = new Matrix(2, 1, 2, 3, 4, 5, 6);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(3, 5, 3, 1, 6, 4, 2), m);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(2, 6, 5, 4, 3, 2, 1), m);
            m.Rotate(MatrixRotate.Right90);
            Assert.AreEqual(new Matrix(3, 2, 4, 6, 1, 3, 5), m);
        }

        #endregion
    }
}
